package com.terry.handler;

import java.nio.charset.Charset;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import com.terry.utils.DateUtils;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.util.ReferenceCountUtil;
/**
 * @author pengpanting
 * 这是向目标发送请求并处理返回结果的处理类，并把target发挥的内容写到浏览器
 */
public class HttpClientHandler extends ChannelInboundHandlerAdapter {
	private static final String CRTL = "\r\n";
	private List<ByteBuf> requestBody;
	private ChannelHandlerContext serverChannelHandlerContext;
	private StringBuffer responseHeader = new StringBuffer();
	private long totalLength = -1;
	private Long length = 0L;
	private boolean closeFlag = false;
	private boolean isChunked;
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		try {
			for(ByteBuf bb : requestBody) {
				ctx.write(bb);
			}
			requestBody.clear();
			ctx.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		try {
			if(msg instanceof HttpResponse) {
				HttpResponse re = (HttpResponse)msg;
				HttpHeaders header = re.headers();
				if(HttpHeaders.isContentLengthSet(re)) {
					totalLength = HttpHeaders.getContentLength(re);
				} else {
					totalLength = Integer.MAX_VALUE;
				}
				String responesLine = re.protocolVersion() + " " + re.status().code() + " " + re.decoderResult();
				responseHeader.append(responesLine).append(CRTL);
				Iterator<Entry<String, String>> kk = header.iteratorAsString();
				while(kk.hasNext()) {
					Entry<String, String> item = kk.next();
					String headerString = item.getKey() + ": " + item.getValue();
					if ("Transfer-Encoding".equals(item.getKey()) && "chunked".equals(item.getValue())) {
						isChunked = true;
					}
					responseHeader.append(headerString).append(CRTL);
				}
				responseHeader.append(CRTL);
				System.out.println("responesHeader(返回头部): " + DateUtils.formatDate(new Date()) +"\n" + responseHeader.toString());
				this.serverChannelHandlerContext.write(Unpooled.wrappedBuffer(responseHeader.toString().getBytes("UTF-8")));
			} else if(msg instanceof HttpContent) {
				HttpContent content = (HttpContent)msg;
				ByteBuf bb = content.content();
				length += bb.readableBytes();
				if(length == 0L) {
					closeFlag = true;
				}
				ByteBuf temp = bb.copy();
				System.out.println("responseBody(返回body): " + DateUtils.formatDate(new Date()) +"\n" + temp.toString(Charset.forName("UTF-8")));
				if (isChunked) { //chunked 数据
					ByteBuf byteBuf = ctx.alloc().buffer((8+length.intValue()));
					String lengthStr = Integer.toHexString(length.intValue());
					byteBuf.writeBytes(lengthStr.getBytes());
					byteBuf.writeBytes(CRTL.getBytes());
					byteBuf.writeBytes(temp);
					byteBuf.writeBytes(CRTL.getBytes());
					this.serverChannelHandlerContext.writeAndFlush(byteBuf);
					length = 0L;
				} else {
					this.serverChannelHandlerContext.writeAndFlush(temp);
				}
			} else {
				
			}
		} catch(Exception e) {
			e.printStackTrace();
		} finally {
			ReferenceCountUtil.release(msg);
		}
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		try {
			this.serverChannelHandlerContext.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(length >= totalLength || closeFlag) {
				this.serverChannelHandlerContext.close();
			}
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		cause.printStackTrace();
		ctx.close();
	}

	public List<ByteBuf> getRequestBody() {
		return requestBody;
	}

	public void setRequestBody(List<ByteBuf> requestBody) {
		this.requestBody = requestBody;
	}

	public ChannelHandlerContext getServerChannelHandlerContext() {
		return serverChannelHandlerContext;
	}

	public void setServerChannelHandlerContext(ChannelHandlerContext serverChannelHandlerContext) {
		this.serverChannelHandlerContext = serverChannelHandlerContext;
	}

	
}
